﻿using System;
using System.Collections.Generic;
using System.Text;
using ContentRenderingApi.Extender;
using ContentRenderingApi.Skeleton;

namespace ContentRenderingApi.Data.Comparer
{
    /// <summary/>
    internal class ChildSortComparer : IComparer<AbstractData>
    {
        private ChildSortSkeleton _childSortSkeleton;
        private ChildSortComparer _successor;

        /// <summary/>
        internal ChildSortComparer(ChildSortSkeleton childSortSkeleton)
        {
            this._childSortSkeleton = childSortSkeleton;
        }

        /// <summary/>
        internal ChildSortComparer Successor
        {
            set { this._successor = value; }
        }

        /// <summary/>
        private static object[] FetchChildRawValue(
            AbstractData data,
            NameTypeExtender[] nameTypeExtenders)
        {
            List<object> rawValues = new List<object>();

            foreach (NameTypeExtender childNameType in nameTypeExtenders)
            {
                IEnumerator<AbstractData> enumerator = data.FetchChildData(childNameType.ChildName);

                // return nothing if no records
                if (!enumerator.MoveNext())
                {
                    rawValues.Add(null);
                }
                else
                {
                    rawValues.Add(enumerator.Current.RawValue);
                }
            }

            return rawValues.ToArray();
        }

        /// <summary/>
        public int Compare(AbstractData dataOne, AbstractData dataTwo)
        {
            // fetch the childs values
            object[] valuesOne = ChildSortComparer.FetchChildRawValue(
                dataOne,
                this._childSortSkeleton.NameTypeExtenders);

            // fetch the childs values
            object[] valuesTwo = ChildSortComparer.FetchChildRawValue(
                dataTwo,
                this._childSortSkeleton.NameTypeExtenders);

            for (int index = 0; index < this._childSortSkeleton.NameTypeExtenders.Length; index++)
            {
                // read the values
                object valueOne = valuesOne[index];
                object valueTwo = valuesTwo[index];
                Type type = this._childSortSkeleton.NameTypeExtenders[index].Type;

                // check the first value
                bool valueOneOk = (valueOne != null) && type.IsInstanceOfType(valueOne);
                bool valueTwoOk = (valueTwo != null) && type.IsInstanceOfType(valueTwo);

                // are both types correct
                if (!valueOneOk && !valueTwoOk)
                {
                    // was a successor provided
                    if (this._successor != null)
                    {
                        return this._successor.Compare(dataOne, dataTwo);
                    }

                    return Constant.COMPARE_EQUAL;
                }
                else if (valueOneOk && !valueTwoOk)
                {
                    return Constant.COMPARE_LEFT;
                }
                else if (!valueOneOk && valueTwoOk)
                {
                    return Constant.COMPARE_RIGHT;
                }
            }

            int result = this._childSortSkeleton.Compare(valuesOne, valuesTwo);

            // if the values are NOT equal then we are done
            if (result != Constant.COMPARE_EQUAL)
            {
                return result;
            }

            // was a successor provided ... if so use it to resolve the compare
            if (this._successor != null)
            {
                return this._successor.Compare(dataOne, dataTwo);
            }

            // no successor ... so the values are equal
            return Constant.COMPARE_EQUAL;
        }
    }
}
